#include <stdio.h>
#include <time.h>
#include <sys/time.h>


#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "debug.h"
    
char* getAsctime(char *buf, int len) {
    struct timeval now;
    struct tm *tm_ptr;
    time_t t;

    gettimeofday(&now, NULL);
    t = now.tv_sec;

    tm_ptr = gmtime(&t);
    if (strftime(buf, len, "%Y-%m-%d %H:%M:%S", tm_ptr))
        return buf;
    else
        return NULL;
} 
int rsm_c_getPidFromFile(const char *pidfilename)
{
    FILE *fin;
    int pid = -1;

    if( NULL != (fin=fopen(pidfilename, "r")) ) {
        fscanf(fin, "%10d", &pid);
        fclose(fin);
    }
    return pid;
}




/*
 * The purpose of this file is to collect and provide common
 * APIs for reading from and/or writing to files. 
 */


/***********************************************************
 *  API to Output to Stdout (or any FILE *)                *
 ***********************************************************/

/* Open a pipe for read and dump to 'of' outfile. */
void
rsm_fio_pdumptofile(FILE *of, const char *pipename)
{
    FILE *fin;
    char line[10*1024]; // big enough for hz-4bss VLAN profile, /proc/net/stats
    if (NULL != (fin=popen(pipename, "r"))) {
        memset(line,0,sizeof(line));
        while( fgets(line, sizeof(line)-1, fin) ) {
            fputs(line, of);
        }
        pclose(fin);
    } else {
        fprintf(of, "Cannot open %s: %s\n", pipename, strerror(errno));
    }
}


static void
rsm_fio_fdump2file(FILE *of, const char *in_file, int lines)
{
    FILE *fin;
    char line[1024];

    if( NULL == (fin=fopen(in_file, "r")) ) {
        fprintf(of, "Cannot open %s: %s\n", in_file, strerror(errno));
    } else {
        while( fgets(line, sizeof(line), fin) ) {
            fprintf(of, "%s", line);
            if( 0 == (--lines) ) break;
        }
        fclose(fin);
    }
}


/* Open a file for read and dump to 'of' outfile. */
void
rsm_fio_fdumptofile(FILE *of, const char *filename)
{
    rsm_fio_fdump2file(of, filename, 0);
}


/* Same as above, with line limit */
void
rsm_fio_fdumptofile2(FILE *of, const char *filename, int max_lines)
{
    rsm_fio_fdump2file(of, filename, max_lines);
}



/***********************************************************
 *  Advisory lock API                                      *
 ***********************************************************/

static int
rsm_flock(int fd, int operation, int trial_limit)
{
    int i;
    for(i = 0; i < trial_limit; i++) {
        if( -1 == flock(fd, operation) ) {
            usleep(1);
            continue;
        }
        return RSM_NOERROR;
    }
    return RSM_ERROR_SYSERR;
}


static void
rsm_flock_release(int fd)
{
    if( -1 == flock(fd, LOCK_UN) )
        DEBUGRED("flock(fd, LOCK_UN): errno %d %s",
                  errno, strerror(errno));
}


/***********************************************************
 *  API to read from a file                                *
 ***********************************************************/

/*
 * note: this API will only read up to len-1 bytes and set last byte to \0
 */
int
rsm_fio_getFile(const char *pname, char *value, int len)
{
    int fd, nread, rv1= RSM_ERROR_SYSERR;

    memset(value, 0, len);
    if( 0 > (fd=open(pname, O_RDONLY, 0)) ) {
        DEBUGRED("open failed. %s (errno=%d)", pname, errno);
    } else if( rsm_isError(rsm_flock(fd, LOCK_SH, 1000 /* 1 sec */)) ) {
        DEBUGRED( "flock(%s, LOCK_SH): errno %d %s",
                  pname, errno, strerror(errno));
        close(fd);
    } else {
        /*
         * TBD: modify the make sure read up to requested size
         */
        if( 0 > (nread = read(fd, value, len-1)) ) {
            rv1 = RSM_ERROR_SYSERR;
        } else {
            value[nread] = '\0';
            rv1 = RSM_NOERROR;
        }

        rsm_flock_release(fd);
        close(fd);
    }
    return rv1;
}


int
rsm_fio_getLine(const char *filename, char *buf, int len)
{
    FILE *fin;
    int rv1 = RSM_ERROR_SYSERR;;

    memset(buf, 0, len);
    if( NULL == (fin=fopen(filename, "r")) ) {
    } else if( rsm_isError(rsm_flock(fileno(fin), LOCK_SH, 1000)) ) {
        DEBUGRED( "flock(%s, LOCK_SH): errno %d %s",
                  filename, errno, strerror(errno));
        fclose(fin);
    } else {
        if( NULL == fgets(buf, len, fin) ) {
        } else {
            rv1 = RSM_NOERROR;
        }

        rsm_flock_release(fileno(fin));
        fclose(fin);
    }
    return rv1;
}


int
rsm_fio_getStr(const char *filename, char *buf, int len)
{
    int rv1 = RSM_NOERROR;
    char line[256], *cp_src, *cp_dst;

    if( rsm_isError(rv1=rsm_fio_getLine(filename, line, sizeof(line))) ) {
    } else {
        cp_src = line;
        cp_dst = buf;
        memset(buf, 0, len);
        while( isspace(*cp_src) ) cp_src++;
        while( len > 1 && !isspace(*cp_src) ) *cp_dst++ = *cp_src++;
        *cp_dst = '\0';
    }
    return rv1;
}


int
rsm_fio_getInt(const char *filename, int *v)
{
    int rv1 = RSM_NOERROR;
    char line[256];

    if( rsm_isError(rv1=rsm_fio_getLine(filename, line, sizeof(line))) ) {
    } else {
        *v = strtoul(line, NULL, 0);
    }
    return rv1;
}


int
rsm_fio_touch(const char* name, const char *data)
{
    int fd, n, rv1 = RSM_ERROR_SYSERR;

    fd = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0600);
    if ( fd >= 0 ) {
        if( rsm_isError(rsm_flock(fd, LOCK_EX, 1000)) ) {
            DEBUGRED( "flock(%s, LOCK_EX): errno %d %s",
                      name, errno, strerror(errno));
        } else {
            rv1 = RSM_NOERROR;
            if( data && strlen(data) ) {
                n = strlen(data);
                if( n != write(fd, data, n) ) rv1 = RSM_ERROR_SYSERR;
            }
            rsm_flock_release(fd);
        }
        close(fd);
    }
    return rv1;
}


/*
 * for writing a memory block
 *   (small block, unless code iterates to try residual)
 */
int
rsm_fio_touch2(const char* name, const char *data, int len)
{
    int fd, n, rv1 = RSM_ERROR_SYSERR;

    fd = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0600);
    if ( fd >= 0 ) {
        if( rsm_isError(rsm_flock(fd, LOCK_EX, 1000)) ) {
            DEBUGRED( "flock(%s, LOCK_EX): errno %d %s",
                      name, errno, strerror(errno));
        } else {
            rv1 = RSM_NOERROR;
            if( data && len ) {
                n = len;
                if( n != write(fd, data, n) ) rv1 = RSM_ERROR_SYSERR;
            }
            rsm_flock_release(fd);
        }
        close(fd);
    }
    return rv1;
}


int
rsm_fio_touchInt(const char* name, int v)
{
    char buf[32];
    snprintf(buf, sizeof(buf), "%d", v);
    return rsm_fio_touch(name, buf);
}


void
rsm_fio_printHex(const unsigned char *buf, int len)
{
    int i;
    for( i=0; i<len; i++ )
        printf("%02X", buf[i]);
}
#if 0
// it should be 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54.
                // minrate is    0,1,  2,    3,  4, 5, 6,  7,   8,    9, 10, 11
                if(!strncmp(child->valuestring, "1mbps", 6)) {
                    configParam->vaps[i].minrate = 0;
                } else if(!strncmp(child->valuestring, "2mbps", 6)) {
                    configParam->vaps[i].minrate = 1;
                } else if(!strncmp(child->valuestring, "5.5mbps", 8)) {
                    configParam->vaps[i].minrate = 2;
                } else if(!strncmp(child->valuestring, "6mbps", 6)) {
                    configParam->vaps[i].minrate = 3;
                } else if(!strncmp(child->valuestring, "9mbps", 6)) {
                    configParam->vaps[i].minrate = 4;
                } else if(!strncmp(child->valuestring, "11mbps", 7)) {
                    configParam->vaps[i].minrate = 5;
                } else if(!strncmp(child->valuestring, "12mbps", 7)) {
                    configParam->vaps[i].minrate = 6;
                } else if(!strncmp(child->valuestring, "18mbps", 7)) {
                    configParam->vaps[i].minrate = 7;
                } else if(!strncmp(child->valuestring, "24mbps", 7)) {
                    configParam->vaps[i].minrate = 8;
                } else if(!strncmp(child->valuestring, "36mbps", 7)) {
                    configParam->vaps[i].minrate = 9;
                } else if(!strncmp(child->valuestring, "48mbps", 7)) {
                    configParam->vaps[i].minrate = 10;
                } else if(!strncmp(child->valuestring, "54mbps", 7)) {
                    configParam->vaps[i].minrate = 11;
                } else {
                    WSGERROR(LOGGETCONF,
                            "Invalid parameter settings:'%s' %s\n", keyName,
                            child->valuestring);
                    return WSG_RetCode_GETCONF_INVALID_PARAM;
                }
                /* when BSS-min-rate == 0 and OFDM-only == 0, 
                               bss_minrate should be 2mbps */
                if (configParam->vaps[i].ofdmOnly == 0 && 
                    configParam->vaps[i].bss_minrate == 0 &&
                    strncmp(child->valuestring, "2mbps", 6)) {
                    WSGERROR(LOGGETCONF,
                            "BSS-min-rate == 0 and OFDM-only == 0"
                            "Invalid parameter settings:'%s' %s\n", keyName,
                            child->valuestring);
                    return WSG_RetCode_GETCONF_INVALID_PARAM;
                    
                }
                /* when BSS-min-rate == 0 and OFDM-only == 0, 
                               bss_minrate should be 2mbps */
                if (configParam->vaps[i].ofdmOnly == 0 && 
                    configParam->vaps[i].bss_minrate == 0 &&
                    strncmp(child->valuestring, "2mbps", 6)) {
                    WSGERROR(LOGGETCONF,
                            "BSS-min-rate == 0 and OFDM-only == 0"
                            "Invalid parameter settings:'%s' %s\n", keyName,
                            child->valuestring);
                    return WSG_RetCode_GETCONF_INVALID_PARAM;
                    
                }
//#endif


/* When VAP is pure G and in 2.4 GHz: minrate is set to 6 Mbps */
static int lwapp_set_ofdmonly(rsm_xact_t *xact, LWAPP_WTP_RADIO_CFG_T *radio_cfg,
                              LWAPP_WTP_VAP_CFG_T *vap_cfg)
{
    int rc = LWAPP_NO_ERROR;
    int enable = (vap_cfg->ofdm_rate_only ? TRUE : FALSE);

    if (LWAPP_IS_24G_RADIO_TYPE(radio_cfg->radio_type)) {
        if (rsm_isError(rsm_wlan_ssetMinRate(vap_cfg->if_name, VAPMINRATE))) {
            rc = LWAPP_ERROR;
            return(rc);
        }

        LWAPP_LOG_DEBUG(LWAPP_LOG_COMP_SYS, "OFDM Only is %sabled",
                        enable ? "En" : "Dis");
        if (rsm_isError(rsm_wlan_ssetPureG(vap_cfg->if_name, enable))) {
            rc = LWAPP_ERROR;
        }
    }
    return(rc);
}

static int lwapp_set_bss_minrate(rsm_xact_t *xact, LWAPP_WTP_RADIO_CFG_T *radio_cfg,
                                 LWAPP_WTP_VAP_CFG_T *vap_cfg)
{
    int val, rc = LWAPP_NO_ERROR;

    if (LWAPP_IS_24G_RADIO_TYPE(radio_cfg->radio_type)) {
        if (rsm_isError(rsm_wlan_ssetMinRate(vap_cfg->if_name, VAPMINRATE))) {
            rc = LWAPP_ERROR;
            return(rc);
        }
    } else if (LWAPP_IS_5G_RADIO_TYPE(radio_cfg->radio_type)) {
        if (rsm_isError(rsm_wlan_ssetMinRate(vap_cfg->if_name, VAPMINRATE_5G))) {
            rc = LWAPP_ERROR;
            return(rc);
        }
    }

    if (vap_cfg->bss_minrate > 0) {
        val = vap_cfg->bss_minrate / 2;
        if (val != 5) {
            LWAPP_LOG_DEBUG(LWAPP_LOG_COMP_SYS, "BSS minimum rate is %d Mbps", val);
        } else {
            LWAPP_LOG_DEBUG(LWAPP_LOG_COMP_SYS, "BSS minimum rate is 5.5 Mbps");
        }
    } else {
        LWAPP_LOG_DEBUG(LWAPP_LOG_COMP_SYS, "BSS minimum rate is Disabled");
    }
    if (rsm_isError(rsm_wlan_setBssMinRate(xact, vap_cfg->if_name, (vap_cfg->bss_minrate * 1000 / 2)))) {
        rc = LWAPP_ERROR;
    }
    return(rc);
/* syslogFacility is in range -1 to 7, local0 start at 16, so it should add it.
    when syslogFacility is -1, it means keeping Original. */
if (configParam->syslogFacility != -1) {
    configParam->syslogFacility += 16;
}
#endif